﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net.Sockets;
using System.Threading;
using HJ212_Common;
using SailHero.Soft.ESB.Collections;
using SailHero.Soft.ESB.Communication.ClientAndServer.Communication.Channels;
using SailHero.Soft.ESB.Communication.ClientAndServer.Communication.Protocols;


namespace SailHero.Soft.ESB.Communication.ClientAndServer.Server
{
    /// <summary>
    /// This class provides base functionality for server classes.
    /// </summary>
    internal abstract class ServerBase : IServer
    {
        #region Public events
        public log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// This event is raised when a new client is connected.
        /// </summary>
        public event EventHandler<ServerClientEventArgs> ClientConnected;

        /// <summary>
        /// This event is raised when a client disconnected from the server.
        /// </summary>
        public event EventHandler<ServerClientEventArgs> ClientDisconnected;

        #endregion

        #region Public properties

        /// <summary>
        /// Gets/sets wire protocol that is used while reading and writing messages.
        /// </summary>
        public IWireProtocolFactory WireProtocolFactory { get; set; }

        /// <summary>
        /// A collection of clients that are connected to the server.
        /// </summary>
        public ThreadSafeSortedList<string, IServerClient> Clients { get; private set; }

        #endregion

        #region Private properties

        /// <summary>
        /// This object is used to listen incoming connections.
        /// </summary>
        private IConnectionListener _connectionListener;

        /// <summary>
        /// This timer is used to send PingMessage messages to server periodically.
        /// </summary>
        private readonly System.Timers.Timer _pingTimer;

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor.
        /// </summary>
        protected ServerBase()
        {
            Clients = new ThreadSafeSortedList<string, IServerClient>();
            WireProtocolFactory = WireProtocolManager.GetDefaultWireProtocolFactory();
            _pingTimer = new System.Timers.Timer();
            _pingTimer.Interval = 3 * 1000;
            _pingTimer.Elapsed += PingTimer_Elapsed;
        }

        #endregion

        #region Public methods
        /// <summary>
        ///  server IsRuning ?.
        /// </summary>
        public virtual bool IsRuning()
        {
            if (_connectionListener == null)
            {
                return false;
            }
            return _connectionListener.IsRuning();

        }

        /// <summary>
        /// 超时登录时间
        /// </summary>
        public int LoginTimeOut
        {
            get;
            set;
        }
        /// <summary>
        /// Handles Elapsed event of _pingTimer to send PingMessage messages to server.
        /// </summary>
        /// <param name="sender">Source of event</param>
        /// <param name="e">Event arguments</param>
        private void PingTimer_Elapsed(object sender, EventArgs e)
        {
            GoPing();
        }
        /// <summary>
        /// 执行ping
        /// </summary>
        private void GoPing()
        {


            try
            {
                ThreadStart Thsrd = new ThreadStart(CheckConnected);
                Thread Thrd = new Thread(Thsrd);
                Thrd.Start();
            }
            catch (Exception ex)
            {
                log.Error("通信出现异常", ex);
            }
        }




        /// <summary>
        /// Starts the server.
        /// </summary>
        public virtual void Start()
        {
            try
            {
                _connectionListener = CreateConnectionListener();
                _connectionListener.CommunicationChannelConnected += ConnectionListener_CommunicationChannelConnected;
                _connectionListener.Start();
                _pingTimer.Start();
            }
            catch (Exception ex)
            {
                log.Error("出现异常", ex);
            }
        }

        /// <summary>
        /// Stops the server.
        /// </summary>
        public virtual void Stop()
        {

            _pingTimer.Stop();
            _pingTimer.Dispose();
            if (_connectionListener != null)
            {
                _connectionListener.Stop();

            }

            foreach (var client in Clients.GetAllItems())
            {
                client.Disconnect();
            }
        }




        #endregion

        #region Protected abstract methods

        /// <summary>
        /// This method is implemented by derived classes to create appropriate connection listener to listen incoming connection requets.
        /// </summary>
        /// <returns></returns>
        protected abstract IConnectionListener CreateConnectionListener();

        #endregion

        #region Private methods

        /// <summary>
        /// Handles CommunicationChannelConnected event of _connectionListener object.
        /// </summary>
        /// <param name="sender">Source of event</param>
        /// <param name="e">Event arguments</param>
        private void ConnectionListener_CommunicationChannelConnected(object sender, CommunicationChannelEventArgs e)
        {

            try
            {
                var client = new ServerClient(e.Channel, this.LoginTimeOut)
                                    {
                                        ClientId = ServerManager.GetClientId(),
                                        WireProtocol = WireProtocolFactory.CreateWireProtocol()
                                    };
                client.Disconnected += Client_Disconnected;
                client.LoginTimeOut = LoginTimeOut;
                Clients[client.ClientId] = client;
                OnClientConnected(client);
                e.Channel.Start();
            }
            catch (Exception ex)
            {

                log.Error("出现异常", ex);
            }
        }

        /// <summary>
        /// Handles Disconnected events of all connected clients.
        /// </summary>
        /// <param name="sender">Source of event</param>
        /// <param name="e">Event arguments</param>
        private void Client_Disconnected(object sender, EventArgs e)
        {
            var client = (IServerClient)sender;
            Clients.Remove(client.ClientId);
            OnClientDisconnected(client);
        }

        #endregion

        #region Event raising methods

        /// <summary>
        /// Raises ClientConnected event.
        /// </summary>
        /// <param name="client">Connected client</param>
        protected virtual void OnClientConnected(IServerClient client)
        {
            var handler = ClientConnected;
            if (handler != null)
            {
                handler(this, new ServerClientEventArgs(client));
            }


        }

        /// <summary>
        /// Raises ClientDisconnected event.
        /// </summary>
        /// <param name="client">Disconnected client</param>
        protected virtual void OnClientDisconnected(IServerClient client)
        {
            var handler = ClientDisconnected;
            if (handler != null)
            {
                handler(this, new ServerClientEventArgs(client));
            }
        }


        /// <summary>
        /// 监测联通性
        /// </summary>
        private void CheckConnected()
        {
            try
            {
                if (this.Clients.Count <= 0) return;
                List<IServerClient> lst = this.Clients.GetAllItems();
                foreach (IServerClient scsServerClient in lst)
                {



                    if (scsServerClient.DefautltReSendTimes >= 2 ||
                scsServerClient.ReSendTimes >= 3)
                    {
                        scsServerClient.Disconnect();
                    }
                    else
                    {
                        try
                        {
                            var ddd = scsServerClient.
                                  ClientSocket.
                                  GetSocketOption(SocketOptionLevel.Socket,
                                                  SocketOptionName.KeepAlive);

                          
                        }
                        catch (Exception ex)
                        {

                            log.Error("通信出现异常", ex);
                        }

                    }




                }
            }
            catch (Exception ex)
            {
                log.Error("通信出现异常", ex);
                //throw;
            }
        }

        #endregion



    }




}
